#include "transferbox.h"
#include <QDesktopServices>
#include <QDir>
#include <QTimer>
#include <QUrl>
#if defined(Q_WS_WIN)
  #include <windows.h>
#endif

TransferBox::TransferBox(int id, QString filepath, QWidget *parent)
        : QGroupBox(parent)
{
    this->file = new QFile(filepath, this);
        this->file->open(QIODevice::ReadOnly);
    this->fileInfo = new QFileInfo(*this->file);
    this->fileSize = this->file->size();
    this->construct(id, this->fileInfo->fileName(), TransferBox::SendDirection);
}

TransferBox::TransferBox(int id, QString filename, quint64 filesize, QWidget *parent)
        : QGroupBox(parent)
{
    this->fileSize = filesize;
    this->file = new QFile(filename, this);
        this->file->open(QIODevice::WriteOnly);
        this->fileInfo = new QFileInfo(*this->file);
    this->construct(id, filename, TransferBox::ReceiveDirection);
}

TransferBox::~TransferBox()
{
   if(this->file->isOpen())
       this->file->close();
    if(this->isTransferring == true && this->direction == TransferBox::ReceiveDirection)
    {
        QDir dir(this->fileInfo->canonicalPath());
        dir.remove(this->fileInfo->fileName());
    }

}

void TransferBox::finishedTransfer()
{
    qDebug("File transfer has finished.");

    this->file->close();
    this->isTransferring = false;
    this->statusLabel->setText(tr("Finished."));



    QObject::disconnect(this, SLOT(cancelTransfer()));
    QObject::connect(this->cancelButton, SIGNAL(clicked()), this, SLOT(removeTransfer()));
    this->cancelButton->setText(tr("Hide"));
    this->cancelButton->setVisible(true);


    if(this->direction == TransferBox::ReceiveDirection)
    {
        QPushButton *openButton = new QPushButton(tr("Open!"), this);
            QObject::connect(openButton, SIGNAL(clicked()), this, SLOT(openFile()));
            this->buttonLay->addWidget(openButton);
    }

}

void TransferBox::removeTransfer()
{
    emit this->remove(this->id);
}
void TransferBox::cancelTransfer()
{
    this->statusLabel->setText(tr("Transfer was canceled"));
    this->isTransferring = false;

    QObject::connect(this->cancelButton, SIGNAL(clicked()), this, SLOT(removeTransfer()));
    this->cancelButton->setText(tr("Hide"));
    this->cancelButton->setVisible(true);


    this->file->close();
    //delete it, if we're recieving..
    if(this->direction == TransferBox::ReceiveDirection)
    {
        QDir dir(this->fileInfo->canonicalPath());
        dir.remove(this->fileInfo->fileName());
    }
    else
    {
        //need to notify the other party we're canceling..
        emit this->cancel(this->id);
    }

}

void TransferBox::openFile()
{
    QString path("file://" + this->fileInfo->canonicalFilePath());

    //TODO: figure out why it doesn't work in Windows with Qt call
    #if defined(Q_WS_WIN)
            ShellExecuteA(0, 0,  qPrintable(path), 0, 0, SW_SHOWNORMAL);
    #else
            QDesktopServices::openUrl(QUrl(path, QUrl::TolerantMode));
    #endif
}

void TransferBox::construct(int id, QString filename, TransferBox::Direction dir)
{

    this->id = id;
    this->direction = dir;
    this->transferred = 0;
    this->isTransferring = true;
    this->transferTimer.start();

    if(dir == TransferBox::SendDirection)
        this->setTitle(tr("Sending"));
    else if (dir == TransferBox::ReceiveDirection)
        this->setTitle(tr("Receiving"));
    else
        qFatal("Hmmm, invalid direction?");


    this->fileLabel = new QLabel(filename, this);

    this->progressBar = new QProgressBar(this);
        //let's make it like a percentage (100 increments)
        this->progressBar->setMinimum(0);
        this->progressBar->setMaximum(100);
        this->progressBar->setFormat(tr("Initializing"));

    this->statusLabel = new QLabel(tr("starting"), this);



    QVBoxLayout *lay = new QVBoxLayout(this);
        lay->addWidget(this->fileLabel);
        lay->addWidget(this->progressBar);
        lay->addWidget(this->statusLabel);
        QWidget *buttonWrapper = new QWidget(this);
        this->buttonLay = new QHBoxLayout(buttonWrapper);
             this->cancelButton = new QPushButton(tr("Cancel"), buttonWrapper);
                if(this->direction == TransferBox::ReceiveDirection) //no ability to cancel (yet)
                    this->cancelButton->hide();
                else
                    QObject::connect(this->cancelButton, SIGNAL(clicked()), this, SLOT(cancelTransfer()));
                this->buttonLay->addWidget(this->cancelButton);
        lay->addWidget(buttonWrapper);


    if(this->fileSize < Q_UINT64_C(10000)) //9,999 bytes or less
    {
       this->sizeDivisor = Q_UINT64_C(1);
       this->postfix = "B"; //Bytes
    }
    else if(this->fileSize < Q_UINT64_C(10240000)) //9,999 KiB or less
    {
       this->sizeDivisor = Q_UINT64_C(1024);
       this->postfix = "KiB";
    }
    else if(this->fileSize < Q_UINT64_C(10485760000)) //9,999 MiB or less
    {
       this->sizeDivisor = Q_UINT64_C(1048576);
       this->postfix = "MiB";
    }
    else if(this->fileSize < Q_UINT64_C(1073741824000)) //9,999 GiB or less
    {
       this->sizeDivisor = Q_UINT64_C(1073741824);
       this->postfix = "GiB";
    }
    else //9,999 TiB or less (and lets not go further, lol)
    {
       this->sizeDivisor = Q_UINT64_C(10995116277760000);
       this->postfix = "TiB";
    }

    this->setLayout(lay);
    //and call it right away..
    this->updateProgress();

}



void TransferBox::updateProgress()
{
    //filesize in units is
    int totalSize = this->fileSize / this->sizeDivisor;
    int doneSize = this->transferred / this->sizeDivisor;

    QString format("%1 / %2 %3");
    format = format.arg(doneSize).arg(totalSize).arg(this->postfix);
    this->progressBar->setValue((this->transferred * 100) / this->fileSize);
    this->progressBar->setFormat(format);

    //bytes per second would be:
    //this->transferred / (this->TransferTime * 1000)
    //but we'll display in KiB/s

    if(this->isTransferring == true) //we'll need to keep updating
        QTimer::singleShot(500, this, SLOT(updateProgress())); //queue it
    else
        return; //no need to update


    if(this->transferTimer.elapsed() > 0) //avoid div by zero
    {
        int speed = (this->transferred * 1000) / (this->transferTimer.elapsed() * 1024) ;
        this->statusLabel->setText(tr("Transfering at %1 KiB/s").arg(speed));
    }
}

void TransferBox::receive(QByteArray bytes)
{
    Q_ASSERT(this->direction == TransferBox::ReceiveDirection);

    this->file->write(bytes);
    this->transferred += bytes.size();
}
QByteArray TransferBox::send()
{
    Q_ASSERT(this->direction == TransferBox::SendDirection);

    QByteArray block = this->file->read(2000);
    this->transferred += block.size();

    if(block.size() == 0) //finished
    {
        this->finishedTransfer();
        emit this->finishedSending(this->id);
    }

    return block;
}

